#pragma once
#include <functional>
#include <iostream>
#include <pthread.h>
#include "Socket.hpp"
using func_t = std::function<std::string(std::string &request)>;

class TcpServer;

class ThreadData
{
public:
    ThreadData(TcpServer *this_tcp, Net_Work::Socket *sock)
        : _this_tcp(this_tcp), _sock(sock)
    {
    }

public:
    TcpServer *_this_tcp;
    Net_Work::Socket *_sock;
};

class TcpServer
{
public:
    TcpServer(uint16_t serverport, func_t httphandler)
        : _serverport(serverport), _listensock(new Net_Work::TcpSocket()), _handler_request(httphandler)
    {
        _listensock->BuildListenSocketMethod(_serverport, Net_Work::backlog);
    }

    static void *ThreadRun(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);

        std::string http_request;
        if (td->_sock->Recv(&http_request, 4096))
        {
            // 报文处理
            std::string http_response = td->_this_tcp->_handler_request(http_request);
            if (!http_response.empty())
            {
                td->_sock->Send(http_response);
            }
        }
        td->_sock->CloseSockFd();
        delete td->_sock;
        delete td;
        return nullptr;
    }

    void Loop()
    {
        while (true)
        {
            uint16_t peerport;
            std::string peerip;
            Net_Work::Socket *newsock = _listensock->AcceptConnection(&peerip, &peerport);
            if (newsock == nullptr)
            {
                std::cout << "获取一个新链接error" << std::endl;
                continue;
            }

            std::cout << "获取一个新链接,sockfd:" << newsock->GetSockfd() << " peer info:" << peerip << ":" << peerport << std::endl;

            pthread_t tid;
            ThreadData *td = new ThreadData(this, newsock);
            pthread_create(&tid, nullptr, ThreadRun, td);
        }
    }
    ~TcpServer()
    {
        delete _listensock;
    }

private:
    int _serverport;
    Net_Work::Socket *_listensock;

public:
    func_t _handler_request;
};
